package xlog

import (
	"fmt"
	"io"
	"log"
	"os"
)

const (
	LOG_LEVEL_INFO = iota
	LOG_LEVEL_ERROR
	LOG_LEVEL_FATAL
)

var ILogger = New(os.Stdout, LOG_LEVEL_INFO)
var ELogger = New(os.Stdout, LOG_LEVEL_ERROR)
var FLogger = New(os.Stdout, LOG_LEVEL_FATAL)

/**
 * 这是 xutils 自己的默认 Logger。许多 xutils 中的模块（如 xnet）会在必要时用到该
 * Logger 打印日志。
 *
 * 如果想要改变 xutils 中模块的日志打印行为，为该变量赋值一个别的 Logger 对象。
 */
var DefaultLogger = ILogger

var callDepth = 2

//=============================================================================

type Logger struct {
	level  int
	writer io.Writer
	logger *log.Logger
}

/**
 * 获得本 Logger 的输出流对象，以便直接写入信息。
 */
func (this *Logger) Writer() io.Writer {
	return this.writer
}

/**
 * 设置日志级别，会影响之后的 Info/Error/Fatal 调用。
 */
func (this *Logger) SetLevel(level int) {
	this.level = level
}

func (this *Logger) Info(v ...interface{}) {
	if this.level <= LOG_LEVEL_INFO {
		args := append([]interface{}{"[I]"}, v...)
		this.logger.Output(callDepth, fmt.Sprintln(args...))
	}
}

func (this *Logger) Infof(format string, v ...interface{}) {
	if this.level <= LOG_LEVEL_INFO {
		this.logger.Output(callDepth, fmt.Sprintf("[I] "+format, v...))
	}
}

func (this *Logger) Infofe(err error, format string, v ...interface{}) {
	if this.level <= LOG_LEVEL_INFO {
		args := append(v, err)
		this.logger.Output(callDepth, fmt.Sprintf("[I] "+format+"\n\t%v", args...))
	}
}

func (this *Logger) Error(v ...interface{}) {
	if this.level <= LOG_LEVEL_ERROR {
		args := append([]interface{}{"[E]"}, v...)
		this.logger.Output(callDepth, fmt.Sprintln(args...))
	}
}

func (this *Logger) Errorf(format string, v ...interface{}) {
	if this.level <= LOG_LEVEL_ERROR {
		this.logger.Output(callDepth, fmt.Sprintf("[E] "+format, v...))
	}
}

func (this *Logger) Errorfe(err error, format string, v ...interface{}) {
	if err != nil && this.level <= LOG_LEVEL_ERROR {
		args := append(v, err)
		this.logger.Output(callDepth, fmt.Sprintf("[E] "+format+"\n\t%v", args...))
	}
}

func (this *Logger) Fatal(v ...interface{}) {
	if this.level <= LOG_LEVEL_FATAL {
		args := append([]interface{}{"[F]"}, v...)
		this.logger.Output(callDepth, fmt.Sprintln(args...))
		os.Exit(1)
	}
}

func (this *Logger) Fatalf(format string, v ...interface{}) {
	if this.level <= LOG_LEVEL_FATAL {
		this.logger.Output(callDepth, fmt.Sprintf("[F] "+format, v...))
		os.Exit(1)
	}
}

func (this *Logger) Fatalfe(err error, format string, v ...interface{}) {
	if err != nil && this.level <= LOG_LEVEL_FATAL {
		args := append(v, err)
		this.logger.Output(callDepth, fmt.Sprintf("[F] "+format+"\n\t%v", args...))
		os.Exit(1)
	}
}

func Info(v ...interface{}) {
	/*
	 * 因为调用层次多了一层，所以要重新设置 callDepth。日志打印完后恢复。
	 * 这是简单处理办法，非线程安全。
	 */
	callDepth = 3
	DefaultLogger.Info(v...)
	callDepth = 2
}

func Infof(format string, v ...interface{}) {
	callDepth = 3
	DefaultLogger.Infof(format, v...)
	callDepth = 2
}

func Infofe(err error, format string, v ...interface{}) {
	callDepth = 3
	DefaultLogger.Infofe(err, format, v...)
	callDepth = 2
}

func Error(v ...interface{}) {
	callDepth = 3
	DefaultLogger.Error(v...)
	callDepth = 2
}

func Errorf(format string, v ...interface{}) {
	callDepth = 3
	DefaultLogger.Errorf(format, v...)
	callDepth = 2
}

func Errorfe(err error, format string, v ...interface{}) {
	callDepth = 3
	DefaultLogger.Errorfe(err, format, v...)
	callDepth = 2
}

func Fatal(v ...interface{}) {
	callDepth = 3
	DefaultLogger.Fatal(v...)
	callDepth = 2
}

func Fatalf(format string, v ...interface{}) {
	callDepth = 3
	DefaultLogger.Fatalf(format, v...)
	callDepth = 2
}

func Fatalfe(err error, format string, v ...interface{}) {
	callDepth = 3
	DefaultLogger.Fatalfe(err, format, v...)
	callDepth = 2
}

func New(w io.Writer, level int) *Logger {
	return &Logger{
		level,
		w,
		log.New(w, "", log.Ltime|log.Lshortfile),
	}
}
